package net.cyndeline.itemEventFactory.actions

import net.cyndeline.itemEventFactory.Action
import net.cyndeline.itemEventFactory.ActionInput
import net.cyndeline.entitySystem.EntityRef
import net.cyndeline.entitySystem.Event
import com.escalatesoft.subcut.inject.BindingModule
import com.escalatesoft.subcut.inject.Injectable
import net.cyndeline.itemEventFactory.ActionResultConfig
import net.cyndeline.itemEventFactory.ActionResultStorage

/**
 * Stores multiple actions, and retrieves events from them all.
 */
trait ActionStorage extends Action {
  
  /**
   * Adds an action to the storage, if no duplicates of it exists.
   */
  def addAction(action: Action)
}

class DefaultActionStorage(implicit val bindingModule: BindingModule) extends ActionStorage with Injectable {
  private var actions = List[Action]()
  
  override def events(indata: ActionInput) = {
    
    /* Make use of the Maps ability to use existing keys if one exists. */
    var eventMapping = Map[EntityRef, List[Event]]()
    
    for (action <- actions) {
      val result = action.events(indata)
      
      for ((target, eventList) <- result.events) {
        if (eventMapping.contains(target)) {
          val currentEvents = eventMapping(target)
          eventMapping += (target -> (currentEvents ++ eventList))
          
        } else {
          eventMapping += (target -> (eventList))
        }
      }
    }
    
    val combinedResult = injectOptional[ActionResultConfig] getOrElse { new ActionResultStorage() }
    
    for ((target, eventList) <- eventMapping.toList) {
      combinedResult.addEvent(target, eventList)
    }
    
    combinedResult
  }
  
  override def addAction(action: Action) {
    if (!actions.contains(action)) {
      actions = actions :+ action
    }
  }

}